package streamforce.crypto.cloud.subscriber;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import streamforce.Stat;
import streamforce.crypto.KPAbe;
import streamforce.crypto.cloud.EPCloud;
import streamforce.crypto.cloud.EPCloudServer;
import streamforce.crypto.cloud.TimeTuple;
import streamforce.crypto.cloud.Tuple;
import streamforce.crypto.event.Ciphertext;
import streamforce.crypto.event.TransformedCTEventAll;
import streamforce.crypto.policies.Policy;

//for query: select sum(price), sum(volume) from StockEvent(cond):win_batch_length(ws)
//assuming that the cryptohandler has been initialized
public class CloudSumPriceAgg1 extends Policy{
	final Log log = LogFactory.getLog(CloudSumPriceAgg1.class);	
	int windowSize;
	int acc;
	byte[][] tmpOriginal, tmpTransformed;
	Stat stat,statTuple;
	public CloudSumPriceAgg1(int pi, int windowSize, KPAbe ch){
		super(ch);
		this.userId = pi;
		this.windowSize = windowSize;
		this.acc = 0;
		this.stat = new Stat("nTransformed");
		this.statTuple = new Stat("nTuples"); 
	}
	
	
	public  void update(int timestamp, int hour, int stockId, Ciphertext ct) {
		TimeTuple tt = EPCloudServer.tupleTime.get(new Tuple(stockId, timestamp)); 
		if (tt.getCount()==0)
			this.statTuple.update(); 			
		tt.increaseCount();
		
		byte[] ciphertext = ct.getCipher();
		long start = System.currentTimeMillis();
		byte[] original= this.cryptoHandler.extractOriginalCipher(this.streamId, ciphertext);
		byte[] transformed=this.cryptoHandler.transform_simple(ciphertext, this.streamId, this.userId);
		if (this.acc%windowSize==0){			
			this.tmpOriginal = new byte[windowSize][original.length];			
			this.tmpTransformed = new byte[windowSize][transformed.length];			
		}		
		this.tmpOriginal[acc%windowSize] = original;
		this.tmpTransformed[acc%windowSize] = transformed;			
		long end = System.currentTimeMillis();		
		log.debug("transformation time = " + (end - start)+", acc = "+this.acc);
		this.stat.update();
		this.acc++;
		// then construct and send another event, only when the window is filled
		if ((this.acc >0) && (this.acc % windowSize == 0)) {	
			byte[] oct = this.cryptoHandler.multiplyCiphers(this.tmpOriginal, this.streamId);
			byte[] tct = this.cryptoHandler.multiplyCiphers(this.tmpTransformed, this.streamId);
			byte[][] originals = new byte[1][oct.length];
			byte[][] transforms = new byte[1][tct.length];
			originals[0] = oct; transforms[0] = tct;
			TransformedCTEventAll cte = new TransformedCTEventAll(
					this.userId, timestamp, hour, stockId, originals, transforms,
					TransformedCTEventAll.SELECT_PRICE);
			EPCloud.getEPServiceProvider().getEPRuntime().sendEvent(cte);
		}		
	}
}
